package com.cjh.wechat.websocket.controller;

import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.Resource;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;
import com.cjh.wechat.commom.pojo.ChatRecord;
import com.cjh.wechat.commom.pojo.Friend;
import com.cjh.wechat.commom.pojo.Group;
import com.cjh.wechat.commom.pojo.User;
import com.cjh.wechat.commom.type.MessType;
import com.cjh.wechat.commom.type.SendMessageType;
import com.cjh.wechat.commom.type.UserStatus;
import com.cjh.wechat.commom.util.BasicUtil;
import com.cjh.wechat.commom.util.JSONUtil;
import com.cjh.wechat.commom.vo.MineVo;
import com.cjh.wechat.commom.vo.ReceiveMessVo;
import com.cjh.wechat.commom.vo.ReceiveMessVo.UserMess;
import com.cjh.wechat.commom.vo.SendMessVo;
import com.cjh.wechat.websocket.service.ChatRecordService;
import com.cjh.wechat.websocket.service.FriendService;
import com.cjh.wechat.websocket.service.GroupService;
import com.cjh.wechat.websocket.service.UnReadService;
import com.cjh.wechat.websocket.service.UserAndGroupService;
import com.cjh.wechat.websocket.service.UserService;

@Resource
public class WebsocketEndPoint extends TextWebSocketHandler
{
    @Resource
    private ChatRecordService                          chatRecordService;
    @Resource
    private GroupService                               groupService;
    @Resource
    private UnReadService                              unReadService;
    @Resource
    private FriendService                              friendService;
    @Resource
    private UserService                                userService;
    @Resource
    private UserAndGroupService                        userAndGroupService;
    private static Logger                              logger = LogManager.getLogger(LogManager.ROOT_LOGGER_NAME);
    private static final Map<String, WebSocketSession> users;
    private static int                                 num    = 0;
    static
    {
        users = new HashMap<String, WebSocketSession>();
    }
    
    @Override
    public void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception
    {
        logger.debug("有消息~~~{}", message.getPayload());
        SendMessVo sendMessVo = JSONUtil.jsonToObj(message.getPayload(), SendMessVo.class);
        // 好友消息
        if (sendMessVo.getType().equals(MessType.FRIEND.value))
        {
            handlerSaveFriendMess(sendMessVo);
            handlerFriendMess(sendMessVo);
        }
        // 群组消息
        else if (sendMessVo.getType().equals(MessType.GROUP.value))
        {
            handlerSaveGroupMess(sendMessVo);
            handlerGroupMess(sendMessVo);
        }
        // 状态修改
        else if (sendMessVo.getType().equals(MessType.CHANGE_STATUS.value))
        {
            notifyStatusTransform(sendMessVo.getMine().getId(), sendMessVo.getToFriend().getStatus());
        }
        else if (sendMessVo.getType().equals(MessType.NOTIFY_DEL_FRIEND.value))
        {
            notifyDelFriend(sendMessVo.getMine().getId(), sendMessVo.getToFriend().getId());
        }
        else if (sendMessVo.getType().equals(MessType.NOTIFY_ADD_FRIEND.value))
        {
            notifyAddFriend(sendMessVo.getMine().getId(), sendMessVo.getToFriend().getId());
        }
        else if (sendMessVo.getType().equals(MessType.NOTIFY_ADD_GROUP.value))
        {
            notifyAddGroup(sendMessVo.getMine().getId(), sendMessVo.getToGroup().getId());
        }
        else if (sendMessVo.getType().equals(MessType.NOTIFY_DEL_MEMBER.value))
        {
            notifyDelMember(sendMessVo.getMine().getId(), sendMessVo.getToGroup().getId());
        }
        else if (sendMessVo.getType().equals(MessType.NOTIFY_DEL_GROUP.value))
        {
            notifyDelGroup(sendMessVo.getToGroup().getId());
        }
        // 请求视频
        else if (sendMessVo.getType().equals(MessType.REQUEST_VIDEO.value))
        {
            handlerRequestVideo(sendMessVo, MessType.REQUEST_VIDEO.value);
        }
        else if (sendMessVo.getType().equals(MessType.ACCEPT_VIDEO.value))
        {
            handlerRequestVideo(sendMessVo, MessType.ACCEPT_VIDEO.value);
        }
        else if (sendMessVo.getType().equals(MessType.REFUSE_VIDEO.value))
        {
            handlerRequestVideo(sendMessVo, MessType.REFUSE_VIDEO.value);
        }
        else if (sendMessVo.getType().equals(MessType.CANCEL_VIDEO.value))
        {
            handlerCancelVideo(sendMessVo);
        }
        // 处理video
        else if (sendMessVo.getType().equals(MessType.OFFER.value))
        {
            handlerVideo(sendMessVo, MessType.OFFER.value);
        }
        else if (sendMessVo.getType().equals(MessType.ANSWER.value))
        {
            handlerVideo(sendMessVo, MessType.ANSWER.value);
        }
        else if (sendMessVo.getType().equals(MessType.CANDIDATE.value))
        {
            handlerVideo(sendMessVo, MessType.CANDIDATE.value);
        }
        // 其他
        else
        {
            // 按照现有的逻辑,程序不应该走到这里
        }
    }
    
    private void handlerCancelVideo(SendMessVo sendMessVo)
    {
        WebSocketSession user = users.get(sendMessVo.getMine().getId());
        WebSocketSession user2 = users.get(sendMessVo.getToFriend().getId());
        if (user != null)
        {
            try
            {
                ReceiveMessVo receiveMessVo = new ReceiveMessVo();
                UserMess userMess = new UserMess();
                userMess.setId(sendMessVo.getMine().getId());
                userMess.setFromid(sendMessVo.getToFriend().getId());
                receiveMessVo.setEmit(MessType.CANCEL_VIDEO.value);
                receiveMessVo.setUserMess(userMess);
                CharSequence charSequence = JSONUtil.objToJson(receiveMessVo);
                TextMessage textMessage = new TextMessage(charSequence);
                logger.debug("发送消息{}", textMessage.getPayload());
                user.sendMessage(textMessage);
            }
            catch (IOException e)
            {
                e.printStackTrace();
            }
        }
        if (user2 != null)
        {
            try
            {
                ReceiveMessVo receiveMessVo = new ReceiveMessVo();
                UserMess userMess = new UserMess();
                userMess.setId(sendMessVo.getToFriend().getId());
                userMess.setFromid(sendMessVo.getMine().getId());
                receiveMessVo.setEmit(MessType.CANCEL_VIDEO.value);
                receiveMessVo.setUserMess(userMess);
                CharSequence charSequence = JSONUtil.objToJson(receiveMessVo);
                TextMessage textMessage = new TextMessage(charSequence);
                logger.debug("发送消息{}", textMessage.getPayload());
                user2.sendMessage(textMessage);
            }
            catch (IOException e)
            {
                e.printStackTrace();
            }
        }
    }
    
    private void handlerRequestVideo(SendMessVo sendMessVo, String emit)
    {
        WebSocketSession user = users.get(sendMessVo.getToFriend().getId());
        if (user != null)
        {
            try
            {
                ReceiveMessVo receiveMessVo = new ReceiveMessVo();
                UserMess userMess = new UserMess();
                userMess.setId(sendMessVo.getToFriend().getId());
                userMess.setFromid(sendMessVo.getMine().getId());
                receiveMessVo.setEmit(emit);
                receiveMessVo.setUserMess(userMess);
                CharSequence charSequence = JSONUtil.objToJson(receiveMessVo);
                TextMessage textMessage = new TextMessage(charSequence);
                logger.debug("发送消息{}", textMessage.getPayload());
                user.sendMessage(textMessage);
            }
            catch (IOException e)
            {
                e.printStackTrace();
            }
        }
    }
    
    // 建立视频连接
    private void handlerVideo(SendMessVo sendMessVo, String emit)
    {
        WebSocketSession user = users.get(sendMessVo.getToFriend().getId());
        if (user != null)
        {
            try
            {
                ReceiveMessVo receiveMessVo = new ReceiveMessVo();
                UserMess userMess = new UserMess();
                userMess.setId(sendMessVo.getToFriend().getId());
                userMess.setFromid(sendMessVo.getMine().getId());
                if (sendMessVo.getMine().getContent() != null && sendMessVo.getMine().getContent() != "")
                {
                    userMess.setContent(sendMessVo.getMine().getContent());
                }
                else
                {
                    userMess.setContent("hello");
                }
                receiveMessVo.setEmit(emit);
                receiveMessVo.setUserMess(userMess);
                CharSequence charSequence = JSONUtil.objToJson(receiveMessVo);
                TextMessage textMessage = new TextMessage(charSequence);
                logger.debug("发送消息{}", textMessage.getPayload());
                user.sendMessage(textMessage);
            }
            catch (IOException e)
            {
                e.printStackTrace();
            }
        }
    }
    
    // 通知被踢出
    private void notifyDelMember(String uid, String gid)
    {
        WebSocketSession user = users.get(uid);
        if (user != null)
        {
            try
            {
                TextMessage textMessage = buildNotifyDelMemberMessage(gid);
                logger.debug("发送消息{}", textMessage.getPayload());
                user.sendMessage(textMessage);
            }
            catch (IOException e)
            {
                e.printStackTrace();
            }
        }
    }
    
    // 通知群解散
    private void notifyDelGroup(String gid) throws Exception
    {
        List<User> member = userAndGroupService.findByGroupId(gid);
        groupService.delGroup(gid);
        for (User user : member)
        {
            WebSocketSession session = users.get(user.getId());
            if (session != null)
            {
                try
                {
                    TextMessage textMessage = buildNotifyDelMemberMessage(gid);
                    logger.debug("发送消息{}", textMessage.getPayload());
                    session.sendMessage(textMessage);
                }
                catch (IOException e)
                {
                    e.printStackTrace();
                }
            }
        }
    }
    
    // 通知被踢出群组
    private TextMessage buildNotifyDelMemberMessage(String gid)
    {
        ReceiveMessVo receiveMessVo = new ReceiveMessVo();
        UserMess userMess = new UserMess();
        userMess.setFromid(gid);
        receiveMessVo.setEmit(MessType.NOTIFY_DEL_MEMBER.value);
        receiveMessVo.setUserMess(userMess);
        CharSequence charSequence = JSONUtil.objToJson(receiveMessVo);
        TextMessage textMessage = new TextMessage(charSequence);
        return textMessage;
    }
    
    // 通知添加群组
    private void notifyAddGroup(String uid, String gid)
    {
        WebSocketSession user = users.get(uid);
        if (user != null)
        {
            try
            {
                TextMessage textMessage = buildNotifyAddGroupMessage(uid, gid);
                logger.debug("发送消息{}", textMessage.getPayload());
                user.sendMessage(textMessage);
            }
            catch (IOException e)
            {
                e.printStackTrace();
            }
        }
    }
    
    // 通知添加好友
    private void notifyAddFriend(String id, String friendId)
    {
        WebSocketSession user = users.get(id);
        WebSocketSession user2 = users.get(friendId);
        if (user != null)
        {
            try
            {
                TextMessage textMessage = buildNotifyAddFriendMessage(id, friendId);
                logger.debug("发送消息{}", textMessage.getPayload());
                user.sendMessage(textMessage);
            }
            catch (IOException e)
            {
                e.printStackTrace();
            }
        }
        if (user2 != null)
        {
            try
            {
                TextMessage textMessage = buildNotifyAddFriendMessage(friendId, id);
                logger.debug("发送消息{}", textMessage.getPayload());
                user2.sendMessage(textMessage);
            }
            catch (IOException e)
            {
                e.printStackTrace();
            }
        }
    }
    
    // 更新双方的好友列表(如果在线的话)
    private void notifyDelFriend(String id, String friendId)
    {
        friendService.delFriend(id, friendId);
        WebSocketSession user = users.get(id);
        WebSocketSession user2 = users.get(friendId);
        if (user != null)
        {
            try
            {
                TextMessage textMessage = buildNotifyDelFriendMessage(friendId);
                logger.debug("发送消息{}", textMessage.getPayload());
                user.sendMessage(textMessage);
            }
            catch (IOException e)
            {
                e.printStackTrace();
            }
        }
        if (user2 != null)
        {
            try
            {
                TextMessage textMessage = buildNotifyDelFriendMessage(id);
                logger.debug("发送消息{}", textMessage.getPayload());
                user2.sendMessage(textMessage);
            }
            catch (IOException e)
            {
                e.printStackTrace();
            }
        }
    }
    
    // 新增群组后,更新群组列表
    private TextMessage buildNotifyAddGroupMessage(String id, String gid)
    {
        ReceiveMessVo receiveMessVo = new ReceiveMessVo();
        UserMess userMess = new UserMess();
        Group group = groupService.getByGid(gid);
        userMess.setAvatar(group.getAvatar());
        userMess.setUsername(group.getName());
        userMess.setFromid(gid);
        receiveMessVo.setEmit(MessType.NOTIFY_ADD_GROUP.value);
        receiveMessVo.setUserMess(userMess);
        CharSequence charSequence = JSONUtil.objToJson(receiveMessVo);
        TextMessage textMessage = new TextMessage(charSequence);
        return textMessage;
    }
    
    // 新增好友后,更新好友列表
    private TextMessage buildNotifyAddFriendMessage(String id, String friendId)
    {
        ReceiveMessVo receiveMessVo = new ReceiveMessVo();
        UserMess userMess = new UserMess();
        userMess.setId(id);
        userMess.setFromid(friendId);
        receiveMessVo.setEmit(MessType.NOTIFY_ADD_FRIEND.value);
        receiveMessVo.setUserMess(userMess);
        CharSequence charSequence = JSONUtil.objToJson(receiveMessVo);
        TextMessage textMessage = new TextMessage(charSequence);
        return textMessage;
    }
    
    // 拼装消息向更新用户删除和被删除后的好友列表
    private TextMessage buildNotifyDelFriendMessage(String id)
    {
        ReceiveMessVo receiveMessVo = new ReceiveMessVo();
        UserMess userMess = new UserMess();
        userMess.setFromid(id);
        receiveMessVo.setEmit(MessType.NOTIFY_DEL_FRIEND.value);
        receiveMessVo.setUserMess(userMess);
        CharSequence charSequence = JSONUtil.objToJson(receiveMessVo);
        TextMessage textMessage = new TextMessage(charSequence);
        return textMessage;
    }
    
    // 处理离线消息记录
    private void handlerUnReadMess(String id, WebSocketSession user)
    {
        List<ReceiveMessVo> unReadMesses = unReadService.getUnReadRecord(id);
        for (ReceiveMessVo unReadMess : unReadMesses)
        {
            CharSequence charSequence = JSONUtil.objToJson(unReadMess);
            TextMessage textMessage = new TextMessage(charSequence);
            try
            {
                logger.debug("发送消息{}", textMessage.getPayload());
                user.sendMessage(textMessage);
                unReadService.removeUnReadRecord(id, unReadMess);
            }
            catch (IOException e)
            {
                e.printStackTrace();
            }
        }
    }
    
    // 处理群组消息记录
    private void handlerSaveGroupMess(SendMessVo sendMessVo)
    {
        String myId = sendMessVo.getMine().getId();
        String groupId = sendMessVo.getToGroup().getId();
        String content = sendMessVo.getMine().getContent();
        String type = sendMessVo.getType();
        ChatRecord chatRecord = buildChatRecord(myId, content, type);
        chatRecordService.addGroupRecord(groupId, chatRecord);
    }
    
    // 处理好友消息记录
    private void handlerSaveFriendMess(SendMessVo sendMessVo)
    {
        String myId = sendMessVo.getMine().getId();
        String friendId = sendMessVo.getToFriend().getId();
        String content = sendMessVo.getMine().getContent();
        String type = sendMessVo.getType();
        ChatRecord chatRecord = buildChatRecord(myId, content, type);
        chatRecordService.addFriendRecord(myId, friendId, chatRecord);
        chatRecordService.addFriendRecord(friendId, myId, chatRecord);
    }
    
    // 处理好友消息
    private void handlerFriendMess(SendMessVo sendMessVo)
    {
        ReceiveMessVo receiveMessVo = buildReceiveMess(sendMessVo);
        CharSequence charSequence = JSONUtil.objToJson(receiveMessVo);
        TextMessage textMessage = new TextMessage(charSequence);
        WebSocketSession user = users.get(sendMessVo.getToFriend().getId());
        if (user != null)
        {
            logger.debug("发送消息{}", textMessage.getPayload());
            try
            {
                user.sendMessage(textMessage);
            }
            catch (Exception e)
            {
                e.printStackTrace();
            }
        }
        else
        {
            logger.debug("保存离线消息{}", textMessage.getPayload());
            unReadService.addUnReadRecord(sendMessVo.getToFriend().getId(), //
                    BasicUtil.getMillDateTime(), receiveMessVo);
        }
    }
    
    // 处理群组消息
    private void handlerGroupMess(SendMessVo sendMessVo)
    {
        ReceiveMessVo receiveMessVo = buildReceiveMess(sendMessVo);
        CharSequence charSequence = JSONUtil.objToJson(receiveMessVo);
        TextMessage textMessage = new TextMessage(charSequence);
        String myId = sendMessVo.getMine().getId();
        String groupId = sendMessVo.getToGroup().getId();
        List<MineVo> groupMembers = groupService.findBy(groupId);
        for (MineVo member : groupMembers)
        {
            String memberId = member.getId();
            if (memberId.equals(myId))
            {
                continue;
            }
            WebSocketSession user = users.get(memberId);
            if (user != null)
            {
                logger.debug("发送消息{}", textMessage.getPayload());
                try
                {
                    user.sendMessage(textMessage);
                }
                catch (Exception e)
                {
                    e.printStackTrace();
                }
            }
            else
            {
                logger.debug("保存离线消息{}", textMessage.getPayload());
                unReadService.addUnReadRecord(memberId, //
                        BasicUtil.getMillDateTime(), receiveMessVo);
            }
        }
    }
    
    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception
    {
        Thread.sleep(1000);
        num++;
        String id = (String) session.getAttributes().get("id");
        logger.debug("用户[{}]建立了连接", id);
        logger.debug("在线人数:[{}]", num);
        users.put(id, session);
        // 通知所有好友该用户上线
        notifyStatusTransform(id, UserStatus.ONLINE.value);
        // 初始化好友列表状态
        initFriendListStatus(id, session);
        // 接收离线消息
        handlerUnReadMess(id, session);
    }
    
    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception
    {
        num--;
        String id = (String) session.getAttributes().get("id");
        logger.debug("用户[{}]关闭了连接", id);
        logger.debug("在线人数:[{}]", num);
        users.remove(id);
        // 通知所有好友该用户下线
        notifyStatusTransform(id, UserStatus.HIDE.value);
    }
    
    // 初始化好友列表状态
    private void initFriendListStatus(String id, WebSocketSession session)
    {
        List<Friend> friends = friendService.findByUid(id);
        for (Friend friend : friends)
        {
            User user = userService.findById(friend.getFid());
            UserMess userMess = new UserMess();
            userMess.setId(user.getId());
            userMess.setType(user.getStatus());
            ReceiveMessVo receiveMessVo = new ReceiveMessVo();
            receiveMessVo.setEmit(SendMessageType.STATUS.value);
            receiveMessVo.setUserMess(userMess);
            CharSequence charSequence = JSONUtil.objToJson(receiveMessVo);
            TextMessage textMessage = new TextMessage(charSequence);
            try
            {
                logger.debug("发送消息{}", textMessage.getPayload());
                session.sendMessage(textMessage);
            }
            catch (IOException e)
            {
                e.printStackTrace();
            }
        }
    }
    
    // 通知用户状态更改
    private void notifyStatusTransform(String id, String status)
    {
        // 数据库状态更改
        userService.updateStatusById(id, status);
        // 通知好友该用户上线
        List<Friend> friends = friendService.findByUid(id);
        for (Friend friend : friends)
        {
            String friendId = friend.getFid();
            WebSocketSession user = users.get(friendId);
            if (user != null)
            {
                UserMess userMess = new UserMess();
                userMess.setId(id);
                userMess.setType(status);
                ReceiveMessVo receiveMessVo = new ReceiveMessVo();
                receiveMessVo.setEmit(SendMessageType.STATUS.value);
                receiveMessVo.setUserMess(userMess);
                CharSequence charSequence = JSONUtil.objToJson(receiveMessVo);
                TextMessage textMessage = new TextMessage(charSequence);
                // 发送状态更改通知
                try
                {
                    logger.debug("发送消息{}", textMessage.getPayload());
                    user.sendMessage(textMessage);
                }
                catch (IOException e)
                {
                    e.printStackTrace();
                }
            }
        }
    }
    
    private ReceiveMessVo buildReceiveMess(SendMessVo sendMessVo)
    {
        ReceiveMessVo receiveMessVo = new ReceiveMessVo();
        UserMess userMess = buildUserMess(sendMessVo);
        receiveMessVo.setUserMess(userMess);
        receiveMessVo.setEmit(sendMessVo.getType());
        return receiveMessVo;
    }
    
    private UserMess buildUserMess(SendMessVo sendMessVo)
    {
        UserMess userMess = new UserMess();
        userMess.setUsername(sendMessVo.getMine().getUsername());
        userMess.setAvatar(sendMessVo.getMine().getAvatar());
        if (sendMessVo.getType().equals(MessType.FRIEND.value))
        {
            userMess.setId(sendMessVo.getMine().getId());
        }
        else
        {
            userMess.setId(sendMessVo.getToGroup().getId());
        }
        userMess.setType(sendMessVo.getType());
        userMess.setContent(sendMessVo.getMine().getContent());
        userMess.setMine(false);
        userMess.setFromid(sendMessVo.getMine().getId());
        userMess.setTimestamp(System.currentTimeMillis());
        return userMess;
    }
    
    private ChatRecord buildChatRecord(String id, String content, String type)
    {
        ChatRecord chatRecord = new ChatRecord();
        chatRecord.setContent(content);
        chatRecord.setDateTime(BasicUtil.getMillDateTime());
        chatRecord.setId(id);
        chatRecord.setType(type);
        return chatRecord;
    }
}
